#ifndef DV_LOG_H
#define DV_LOG_H

#include "osyncstream.h"
#include <Socket.h>
using namespace kascale;
#include <iomanip>
using namespace std;

extern osyncstream dvlog;


class SourceStat
{
public:
	SourceStat()
	{
		bytes_recved = 0;
		total_packets = 0;
		lost_packets = 0;
		last_seq = 0;
		start_time = 0;
		stop_time = 0;
		bandwidth = 0.0;
	}
	SourceStat(const SourceStat& ss)
	{
		this->operator=(ss);
	}
	SourceStat& operator=(const SourceStat& ss)
	{
		if(this == &ss)
			return *this;
		ep = ss.ep;
		bytes_recved = ss.bytes_recved;
		total_packets = ss.total_packets;
		lost_packets = ss.lost_packets;
		last_seq = ss.last_seq;
		start_time = ss.start_time;
		stop_time = ss.stop_time;
		bandwidth = ss.bandwidth;
		return *this;
	}
	IPEndPoint	ep;
	int64_t		bytes_recved;
	int32_t		total_packets;
    int32_t		lost_packets;
	int64_t		start_time;
	int64_t		stop_time;
	u_int16_t	last_seq;
	double		bandwidth;
};

class NetworkSourceLog
{
public:
	NetworkSourceLog()
	{
		total_packets = 0;
		lost_packets = 0;
		bytes_recved = 0;
		start_time = 0;
		stop_time = 0;
	}
	NetworkSourceLog(const NetworkSourceLog& nsl)
	{
		this->operator=(nsl);
	}
	NetworkSourceLog& operator=(const NetworkSourceLog& nsl)
	{
		if(this == &nsl)
			return *this;
		ep = nsl.ep;
		total_packets = nsl.total_packets;
		lost_packets = nsl.lost_packets;
		bytes_recved = nsl.bytes_recved;
		start_time = nsl.start_time;
		stop_time = nsl.stop_time;
		bandwidth = nsl.bandwidth;
		return *this;
	}
	IPEndPoint	ep;
	int32_t		total_packets;
	int32_t		lost_packets;
	int64_t		bytes_recved;
	int64_t		start_time;
	int64_t		stop_time;
	vector<pair<int64_t, double> > bandwidth;
};


inline string bandwidth_to_string(double bw)
{
	ostringstream ostr;
	string unit;
	if(bw > 1e12)
	{
		bw /= 1e12;
		unit = "T";
	}
	else if(bw > 1e9)
	{
		bw /= 1e9;
		unit = "G";
	}
	else if(bw > 1e6)
	{
		bw /= 1e6;
		unit = "M";
	}
	else if(bw > 1e5)
	{
		bw /= 1e3;
		unit = "K";
	}
	ostr << setprecision(3) <<  bw << unit;
	return ostr.str();
}

inline ostream& operator<<(ostream& ostr, const NetworkSourceLog& nsl)
{
	ostr << "<source_log ip=\"" << nsl.ep.Address() << "\" port=\"" << nsl.ep.Port() << "\" start=\"";
	DateTime tmpdt(nsl.start_time);
	tmpdt.ToLocalTime();
	ostr << tmpdt.ToShortString() << "\" stop=\"";
	tmpdt.FromTickCount(nsl.stop_time);
	tmpdt.ToLocalTime();
	ostr << tmpdt.ToShortString() << "\" packets=\"" << nsl.total_packets << "\" lost=\"" << setprecision(3) << 100.0 * nsl.lost_packets / nsl.total_packets << "%\" bytes=\"" << nsl.bytes_recved << "\" avg_bw=\"";
	if(nsl.stop_time > nsl.start_time)
	{
		ostr << bandwidth_to_string(8e6 * nsl.bytes_recved / (double)(nsl.stop_time - nsl.start_time)) << "bps";
	}
	else
	{
		ostr << "--";
	}
	ostr << "\">" << endl;
	for(u_int32_t i = 1; i < nsl.bandwidth.size(); ++i)
	{
		tmpdt.FromTickCount(nsl.bandwidth[i].first);
		tmpdt.ToLocalTime();
		ostr << "    <bw_change time=\"" << tmpdt.ToShortString() << "\" bandwidth=\"" << bandwidth_to_string(8e6 * nsl.bandwidth[i].second) << "bps\"/>" << endl;
	}
	ostr << "</source_log>" << endl;
	return ostr;
}

#endif // !defined(DV_LOG_H)

